{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IaK62oX3NhRf"
      },
      "source": [
        "# 基于langchain创建自己专属的对话大模型"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "1. 领域精准问答\n",
        "2. 数据更新频繁\n",
        "3. 生成内容可解释可追溯\n",
        "4. 数据隐私保护"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-173FmLdNhRj"
      },
      "source": [
        "通过这个例子，我们将基于`LangChain`, `OpenAI(LLM)`,  `vector DB`构建一个属于自己的LLM模型。\n",
        "\n",
        "主要使用的技术————***Retrieval Augmented Generation (RAG)***\n",
        "\n",
        "首先确保自己拥有一个 `OpenAI API key` (也并非必须)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fzzHZ2sLNhRk"
      },
      "source": [
        "### 准备环境"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "EAivifIqNhRk",
        "outputId": "53e3378c-79df-43e8-c92a-c0dce00dcaa0"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "    WARNING: No metadata found in c:\\users\\blackink\\.conda\\envs\\langchain\\lib\\site-packages\n",
            "ERROR: Could not install packages due to an OSError: [WinError 32] 另一个程序正在使用此文件，进程无法访问。: 'C:\\\\Users\\\\blackink\\\\.conda\\\\envs\\\\langchain\\\\Lib\\\\site-packages\\\\langchain\\\\tools\\\\wikipedia\\\\__init__.py'\n",
            "Consider using the `--user` option or check the permissions.\n",
            "\n"
          ]
        }
      ],
      "source": [
        "! pip install -qU \\\n",
        "    langchain==0.0.316 \\\n",
        "    openai==0.28.1  \\\n",
        "    tiktoken==0.5.1  \\\n",
        "    cohere \\\n",
        "    chromadb==0.4.15"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1Eg0ay3TNhRm"
      },
      "source": [
        "### 创建一个对话模型(no RAG)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "yd3OUQIWNhRm"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from langchain.chat_models import ChatOpenAI\n",
        "\n",
        "os.environ[\"OPENAI_API_KEY\"] = \"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\"\n",
        "\n",
        "chat = ChatOpenAI(\n",
        "    openai_api_key=os.environ[\"OPENAI_API_KEY\"],\n",
        "    model='gpt-3.5-turbo'\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YAxQlUl1Cwom"
      },
      "source": [
        "OpenAI Python 的例子\n",
        "```python\n",
        "[\n",
        "    {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
        "    {\"role\": \"user\", \"content\": \"Knock knock.\"},\n",
        "    {\"role\": \"assistant\", \"content\": \"Who's there?\"},\n",
        "    {\"role\": \"user\", \"content\": \"Orange.\"},\n",
        "]\n",
        "```\n",
        "https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models\n",
        "\n",
        "\n",
        "但是langchain 需要使用以下的格式"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "jbPKtHYsNhRn"
      },
      "outputs": [],
      "source": [
        "\n",
        "from langchain.schema import (\n",
        "    SystemMessage,\n",
        "    HumanMessage,\n",
        "    AIMessage\n",
        ")\n",
        "\n",
        "\n",
        "messages = [\n",
        "    SystemMessage(content=\"You are a helpful assistant.\"),\n",
        "    HumanMessage(content=\"Knock knock.\"),\n",
        "    AIMessage(content=\"Who's there?\"),\n",
        "    HumanMessage(content=\"Orange\"),\n",
        "    \n",
        "]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "11iDGkWPNhRn",
        "outputId": "e3698bd8-b14b-4abf-957f-041c0abd7f7f"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "AIMessage(content='Orange who?')"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "res = chat(messages)\n",
        "res"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m7db28OOMjig"
      },
      "source": [
        "因为 `res`也是`AIMessage`属性，所以我们可以直接进行添加，即可实现下一次的响应"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "85dW12laNLmO",
        "outputId": "7e431e35-7673-41d3-8ac7-a4b352c1b1be"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Orange you glad I'm here to assist you?\n"
          ]
        }
      ],
      "source": [
        "messages.append(res)\n",
        "res = chat(messages)\n",
        "\n",
        "print(res.content)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1YtYH-1oNhRo",
        "tags": [
          "parameters"
        ]
      },
      "source": [
        "#### 处理LLM存在的缺陷\n",
        "1. 容易出现幻觉\n",
        "2. 信息滞后\n",
        "3. 专业领域深度知识匮乏\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "1PZxdF06NhRp"
      },
      "outputs": [],
      "source": [
        "messages = [\n",
        "    SystemMessage(content=\"你是一个专业的知识助手。\"),\n",
        "    HumanMessage(content=\"你知道baichuan2模型吗？\"),\n",
        "]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Vw-ylWZMQW5z",
        "outputId": "f4ff154a-c8af-457c-a2db-fa310b92ccc3"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "是的，我了解baichuan2模型。baichuan2是一种基于深度学习的图像分割模型，主要用于图像语义分割任务。它采用了编码-解码的架构，通过卷积神经网络提取图像特征，并将特征映射到与输入图像大小相同的分割结果。baichuan2模型在许多图像分割比赛和任务中取得了很好的性能，并被广泛应用于医学图像分割、自动驾驶、图像编辑等领域。\n"
          ]
        }
      ],
      "source": [
        "res = chat(messages)\n",
        "print(res.content)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XXir07e9yKNW"
      },
      "source": [
        "chatgpt AI无法满足我们在某些特定领域的专业需求，我们可以通过知识注入的方式，利用prompt来解决这种问题："
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6MTJRA2nQW_E"
      },
      "outputs": [],
      "source": [
        "\n",
        "baichuan2_information = [\n",
        "    \"Baichuan 2是一个大规模多语言语言模型，它专注于训练在多种语言中表现优异的模型，包括不仅限于英文。这使得Baichuan 2在处理各种语言的任务时能够取得显著的性能提升。\",\n",
        "    \"Baichuan 2是从头开始训练的，使用了包括了2.6万亿个标记的庞大训练数据集。相对于以往的模型，Baichuan 2提供了更丰富的数据资源，从而能够更好地支持多语言的开发和应用。\",\n",
        "    \"Baichuan 2不仅在通用任务上表现出色，还在特定领域（如医学和法律）的任务中展现了卓越的性能。这为特定领域的应用提供了强有力的支持。\"\n",
        "]\n",
        "\n",
        "source_knowledge = \"\\n\".join(baichuan2_information)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "FHKTgq08NhRp",
        "outputId": "d6333937-c854-4b1e-8a12-2bc1d1a33301"
      },
      "outputs": [],
      "source": [
        "print(source_knowledge)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pdgyyDx2yx8M"
      },
      "outputs": [],
      "source": [
        "query = \"你知道baichuan2模型吗？\"\n",
        "\n",
        "prompt_template = f\"\"\"基于以下内容回答问题：\n",
        "\n",
        "内容:\n",
        "{source_knowledge}\n",
        "\n",
        "Query: {query}\"\"\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZwSPm_3qzWB7"
      },
      "outputs": [],
      "source": [
        "prompt = HumanMessage(\n",
        "    content=prompt_template\n",
        ")\n",
        "messages.append(prompt)\n",
        "\n",
        "res = chat(messages)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "P861bTreziWz",
        "outputId": "62aaf1ba-aebe-4576-c5cc-7203f677d205"
      },
      "outputs": [],
      "source": [
        "print(res.content)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-Npmwyy808i6"
      },
      "source": [
        "当我们注入一些专业的知识后，模型就能够很好的回答相关问题。\n",
        "如果每一个问题都去用相关的外部知识进行增强拼接的话，那么回答的准确性就大大增加？？？？"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qXfTkYm01oWp"
      },
      "source": [
        "### 创建一个RAG对话模型"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "i8TTksfT2K3r"
      },
      "source": [
        "#### 1. 加载数据 （以baichuan2论文为例）\n",
        "\n",
        "   https://arxiv.org/pdf/2309.10305v2.pdf"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "iIVOnz1TxkZ4",
        "outputId": "aeeee9d2-98e0-42b1-b8f5-8ef430eb7f98"
      },
      "outputs": [],
      "source": [
        "! pip install pypdf"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VD-UF8z06txb"
      },
      "outputs": [],
      "source": [
        "from langchain.document_loaders import PyPDFLoader\n",
        "\n",
        "loader = PyPDFLoader(\"https://arxiv.org/pdf/2309.10305.pdf\")\n",
        "\n",
        "pages = loader.load_and_split()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KsCy_vTs68I-"
      },
      "outputs": [],
      "source": [
        "pages[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OZN6yzwi7J61"
      },
      "source": [
        "#### 2. 知识切片 将文档分割成均匀的块。每个块是一段原始文本"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wt3G5-ph7gho"
      },
      "outputs": [],
      "source": [
        "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
        "\n",
        "text_splitter = RecursiveCharacterTextSplitter(\n",
        "    chunk_size = 500,\n",
        "    chunk_overlap = 50,\n",
        ")\n",
        "\n",
        "docs = text_splitter.split_documents(pages)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "BCXqYY4D7gkp",
        "outputId": "d92b8a52-fe1e-4480-db30-1aa2f15b6716"
      },
      "outputs": [],
      "source": [
        "len(docs)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lgABYtKp8_Ke"
      },
      "source": [
        "#### 3. 利用embedding模型对每个文本片段进行向量化，并储存到向量数据库中"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AmI_-A1-ziZN"
      },
      "outputs": [],
      "source": [
        "from langchain.embeddings.openai import OpenAIEmbeddings\n",
        "from langchain.vectorstores import Chroma\n",
        "\n",
        "\n",
        "embed_model = OpenAIEmbeddings()\n",
        "vectorstore = Chroma.from_documents(documents=docs, embedding=embed_model , collection_name=\"openai_embed\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G-fgbDgQC77h"
      },
      "source": [
        "#### 4. 通过向量相似度检索和问题最相关的K个文档。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zuoRfbU_Du3S"
      },
      "outputs": [],
      "source": [
        "query = \"How large is the baichuan2 vocabulary?\"\n",
        "result = vectorstore.similarity_search(query ,k = 2)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "dliY5xHaC2NN",
        "outputId": "40191eee-e17e-4283-e63b-f5ff2088bdf5"
      },
      "outputs": [],
      "source": [
        "result"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ymUjel7-E-t1"
      },
      "source": [
        "#### 5. 原始`query`与检索得到的文本组合起来输入到语言模型，得到最终的回答"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9wBIBDnIC2P8"
      },
      "outputs": [],
      "source": [
        "def augment_prompt(query: str):\n",
        "  # 获取top3的文本片段\n",
        "  results = vectorstore.similarity_search(query, k=3)\n",
        "  source_knowledge = \"\\n\".join([x.page_content for x in results])\n",
        "  # 构建prompt\n",
        "  augmented_prompt = f\"\"\"Using the contexts below, answer the query.\n",
        "\n",
        "  contexts:\n",
        "  {source_knowledge}\n",
        "\n",
        "  query: {query}\"\"\"\n",
        "  return augmented_prompt"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JHTutK09GRSx"
      },
      "outputs": [],
      "source": [
        "print(augment_prompt(query))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "sPNBZlRPGlDB",
        "outputId": "8d453129-f6c5-4553-877f-b692c337efdc"
      },
      "outputs": [],
      "source": [
        "# 创建prompt\n",
        "prompt = HumanMessage(\n",
        "    content=augment_prompt(query)\n",
        ")\n",
        "\n",
        "messages.append(prompt)\n",
        "\n",
        "res = chat(messages)\n",
        "\n",
        "print(res.content)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gpwaPwJteHz3"
      },
      "source": [
        "### 没有OPENAI api key怎么办 创建一个非openai的对话模型  "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MgKpiexG-AS_"
      },
      "source": [
        "\n",
        "1.   embedding模型  \n",
        "2.   chat模型\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ExJrgFacesTo"
      },
      "outputs": [],
      "source": [
        "! pip install sentence-transformers"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xvD4mIBCHKjG"
      },
      "outputs": [],
      "source": [
        "from langchain.embeddings import HuggingFaceEmbeddings\n",
        "from langchain.vectorstores import Chroma\n",
        "\n",
        "model_name = \"sentence-transformers/sentence-t5-large\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SzFKi_bQehhX"
      },
      "outputs": [],
      "source": [
        "embedding = HuggingFaceEmbeddings(model_name=model_name)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jJP5K7J5ehlB"
      },
      "outputs": [],
      "source": [
        "vectorstore_hf = Chroma.from_documents(documents=docs, embedding=embedding , collection_name=\"huggingface_embed\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "result = vectorstore_hf.similarity_search(query ,k = 2)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "print(result)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "通过本地部署的模型进行交互"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [
        "i8TTksfT2K3r",
        "OZN6yzwi7J61",
        "lgABYtKp8_Ke",
        "ymUjel7-E-t1"
      ],
      "gpuType": "T4",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.0"
    },
    "orig_nbformat": 4,
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "0e42f4231586464abadc5674077b5b85": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_881fd88d52904346a58d3ed6b7b25b42",
            "max": 7,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_5d32c664e3a94141a49200a3bf815719",
            "value": 5
          }
        },
        "17569993d70142caaca7d550eaf84773": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "462fdec12c174c7f893296108744867b": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "5d32c664e3a94141a49200a3bf815719": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "7a2bda030860431a9ff1bc8719f15d9c": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_17569993d70142caaca7d550eaf84773",
            "placeholder": "​",
            "style": "IPY_MODEL_c972648b06754d43ada362e512fea865",
            "value": " 5/7 [00:49&lt;00:20, 10.03s/it]"
          }
        },
        "7f7bd9c4ac8441ad9d252869f75b17e6": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_853287ee89244e169ffebbd4a7a0335d",
            "placeholder": "​",
            "style": "IPY_MODEL_462fdec12c174c7f893296108744867b",
            "value": "Loading checkpoint shards:  71%"
          }
        },
        "853287ee89244e169ffebbd4a7a0335d": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "881fd88d52904346a58d3ed6b7b25b42": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "c972648b06754d43ada362e512fea865": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "d0c0568f4d6f4bda9253932577becf3c": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_7f7bd9c4ac8441ad9d252869f75b17e6",
              "IPY_MODEL_0e42f4231586464abadc5674077b5b85",
              "IPY_MODEL_7a2bda030860431a9ff1bc8719f15d9c"
            ],
            "layout": "IPY_MODEL_d80d0f6e4afb4e709e6a01e3d651b7bf"
          }
        },
        "d80d0f6e4afb4e709e6a01e3d651b7bf": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        }
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
